#include <iostream>

#define LINE_LENGTH 256
#define LENGTH_OF(x) (sizeof(x)/sizeof(x[0]))
#define TEXT(x) #x
#define REG_LIMIT 8

typedef bool(*PARSE_FUNC)(FILE*, const char*, size_t);

struct Ins {
    unsigned short opcode : 3;
    unsigned short rd : 3;
    unsigned short rs : 3;
    unsigned short funct : 3;
    unsigned short imm : 4;
};

bool parseConst(FILE* out, const char* line, size_t len){
    long long val;
    if (_snscanf(line, len, "db 0x%hhx", &val) == 1){
        fwrite(&val, 1, 1, out);
        return true;
    }
    if (_snscanf(line, len, "db %hhd", &val) == 1){
        fwrite(&val, 1, 1, out);
        return true;
    }
    if (_snscanf(line, len, "dw 0x%hx", &val) == 1){
        fwrite(&val, 2, 1, out);
        return true;
    }
    if (_snscanf(line, len, "dw %hd", &val) == 1){
        fwrite(&val, 2, 1, out);
        return true;
    }
    if (_snscanf(line, len, "dd 0x%x", &val) == 1){
        fwrite(&val, 4, 1, out);
        return true;
    }
    if (_snscanf(line, len, "dd %d", &val) == 1){
        fwrite(&val, 4, 1, out);
        return true;
    }
    if (_snscanf(line, len, "dq 0x%llx", &val) == 1){
        fwrite(&val, 8, 1, out);
        return true;
    }
    if (_snscanf(line, len, "dq %lld", &val) == 1){
        fwrite(&val, 8, 1, out);
        return true;
    }
    return false;
}

bool parseMemory(FILE* out, const char* line, size_t len){
    short offset;
    unsigned short rd, rs;

    if (_snscanf(line, len, "lb r%hu, [pc%hd]", &rd, &offset) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset >= 0x40 || offset < -0x40)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x40, 0x3F);
        Ins ins;
        ins.opcode = 0b011;
        ins.funct = 0b000;
        ins.rd = rd;
        ins.rs = (offset & 0x7);
        ins.imm = ((offset >> 3) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "lb r%hu, [r%hu%hd]", &rd, &rs, &offset) == 3){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset >= 0x8 || offset < -0x8)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x8, 0x7);
        Ins ins;
        ins.opcode = 0b010;
        ins.funct = 0b000;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = (offset & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "lw r%hu, [pc%hd]", &rd, &offset) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
       if (offset >= 0x40 || offset < -0x40)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x40, 0x3F);
        Ins ins;
        ins.opcode = 0b011;
        ins.funct = 0b001;
        ins.rd = rd;
        ins.rs = (offset & 0x7);
        ins.imm = ((offset >> 3) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "lw r%hu, [r%hu%hd]", &rd, &rs, &offset) == 3){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset >= 0x8 || offset < -0x8)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x8, 0x7);
        Ins ins;
        ins.opcode = 0b010;
        ins.funct = 0b001;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = (offset & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "lbu r%hu, [pc%hd]", &rd, &offset) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset >= 0x40 || offset < -0x40)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x40, 0x3F);
        Ins ins;
        ins.opcode = 0b011;
        ins.funct = 0b010;
        ins.rd = rd;
        ins.rs = (offset & 0x7);
        ins.imm = ((offset >> 3) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "lbu r%hu, [r%hu%hd]", &rd, &rs, &offset) == 3){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset >= 0x8 || offset < -0x8)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x8, 0x7);
        Ins ins;
        ins.opcode = 0b010;
        ins.funct = 0b010;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = (offset & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "sb [pc%hd], r%hu", &offset, &rd) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset >= 0x40 || offset < -0x40)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x40, 0x3F);
        Ins ins;
        ins.opcode = 0b011;
        ins.funct = 0b011;
        ins.rd = rd;
        ins.rs = (offset & 0x7);
        ins.imm = ((offset >> 3) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "sb [r%hu%hd], r%hu", &rs, &offset, &rd) == 3){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset >= 0x8 || offset < -0x8)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x8, 0x7);
        Ins ins;
        ins.opcode = 0b010;
        ins.funct = 0b011;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = (offset & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "sw [pc%hd], r%hu", &offset, &rd) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset >= 0x40 || offset < -0x40)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x40, 0x3F);
        Ins ins;
        ins.opcode = 0b011;
        ins.funct = 0b100;
        ins.rd = rd;
        ins.rs = (offset & 0x7);
        ins.imm = ((offset >> 3) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "sw [r%hu%hd], r%hu", &rs, &offset, &rd) == 3){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset >= 0x8 || offset < -0x8)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x8, 0x7);
        Ins ins;
        ins.opcode = 0b010;
        ins.funct = 0b100;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = (offset & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "lea r%hu, [pc%hd]", &rd, &offset) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset >= 0x40 || offset < -0x40)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x40, 0x3F);
        Ins ins;
        ins.opcode = 0b011;
        ins.funct = 0b101;
        ins.rd = rd;
        ins.rs = (offset & 0x7);
        ins.imm = ((offset >> 3) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "lea r%hu, [r%hu%hd]", &rd, &rs, &offset) == 3){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset >= 0x8 || offset < -0x8)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x8, 0x7);
        Ins ins;
        ins.opcode = 0b010;
        ins.funct = 0b101;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = (offset & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    return false;
}

bool parseArithmatic(FILE* out, const char* line, size_t len){
    short imm;
    unsigned short rd, rs;

    if (_snscanf(line, len, "add r%hu, %hd", &rd, &imm) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (imm >= 0x40 || imm < -0x40)
            printf("[ERROR]: '%s' Constant Limit(%d,%d) Exceeded\n", line, -0x40, 0x3F);
        Ins ins;
        ins.opcode = 0b000;
        ins.funct = 0b000;
        ins.rd = rd;
        ins.rs = (imm & 0x7);
        ins.imm = ((imm >> 3) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "and r%hu, %hd", &rd, &imm) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (imm >= 0x40 || imm < -0x40)
            printf("[ERROR]: '%s' Constant Limit(%d,%d) Exceeded\n", line, -0x40, 0x3F);
        Ins ins;
        ins.opcode = 0b000;
        ins.funct = 0b001;
        ins.rd = rd;
        ins.rs = (imm & 0x7);
        ins.imm = ((imm >> 3) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "or r%hu, %hd", &rd, &imm) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (imm >= 0x40 || imm < -0x40)
            printf("[ERROR]: '%s' Constant Limit(%d,%d) Exceeded\n", line, -0x40, 0x3F);
        Ins ins;
        ins.opcode = 0b000;
        ins.funct = 0b010;
        ins.rd = rd;
        ins.rs = (imm & 0x7);
        ins.imm = ((imm >> 3) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "xor r%hu, %hd", &rd, &imm) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (imm >= 0x40 || imm < -0x40)
            printf("[ERROR]: '%s' Constant Limit(%d,%d) Exceeded\n", line, -0x40, 0x3F);
        Ins ins;
        ins.opcode = 0b000;
        ins.funct = 0b011;
        ins.rd = rd;
        ins.rs = (imm & 0x7);
        ins.imm = ((imm >> 3) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "sll r%hu, %hd", &rd, &imm) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (imm >= 0x40 || imm < -0x40)
            printf("[ERROR]: '%s' Constant Limit(%d,%d) Exceeded\n", line, -0x40, 0x3F);
        Ins ins;
        ins.opcode = 0b000;
        ins.funct = 0b100;
        ins.rd = rd;
        ins.rs = (imm & 0x7);
        ins.imm = ((imm >> 3) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "srl r%hu, %hd", &rd, &imm) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (imm >= 0x40 || imm < -0x40)
            printf("[ERROR]: '%s' Constant Limit(%d,%d) Exceeded\n", line, -0x40, 0x3F);
        Ins ins;
        ins.opcode = 0b000;
        ins.funct = 0b101;
        ins.rd = rd;
        ins.rs = (imm & 0x7);
        ins.imm = ((imm >> 3) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "sra r%hu, %hd", &rd, &imm) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (imm >= 0x40 || imm < -0x40)
            printf("[ERROR]: '%s' Constant Limit(%d,%d) Exceeded\n", line, -0x40, 0x3F);
        Ins ins;
        ins.opcode = 0b000;
        ins.funct = 0b110;
        ins.rd = rd;
        ins.rs = (imm & 0x7);
        ins.imm = ((imm >> 3) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "mov r%hu, 0x%hx", &rd, &imm) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (imm >= 0x40 || imm < -0x40)
            printf("[ERROR]: '%s' Constant Limit(%d,%d) Exceeded\n", line, -0x40, 0x3F);
        Ins ins;
        ins.opcode = 0b000;
        ins.funct = 0b111;
        ins.rd = rd;
        ins.rs = (imm & 0x7);
        ins.imm = ((imm >> 3) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "mov r%hu, %hd", &rd, &imm) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (imm >= 0x40 || imm < -0x40)
            printf("[ERROR]: '%s' Constant Limit(%d,%d) Exceeded\n", line, -0x40, 0x3F);
        Ins ins;
        ins.opcode = 0b000;
        ins.funct = 0b111;
        ins.rd = rd;
        ins.rs = (imm & 0x7);
        ins.imm = ((imm >> 3) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }

    if (_snscanf(line, len, "add r%hu, r%hu", &rd, &rs) == 2){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        Ins ins;
        ins.opcode = 0b001;
        ins.funct = 0b000;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = 0;
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "and r%hu, r%hu", &rd, &rs) == 2){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        Ins ins;
        ins.opcode = 0b001;
        ins.funct = 0b001;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = 0;
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "or r%hu, r%hu", &rd, &rs) == 2){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        Ins ins;
        ins.opcode = 0b001;
        ins.funct = 0b010;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = 0;
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "xor r%hu, r%hu", &rd, &rs) == 2){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        Ins ins;
        ins.opcode = 0b001;
        ins.funct = 0b011;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = 0;
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "sll r%hu, r%hu", &rd, &rs) == 2){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        Ins ins;
        ins.opcode = 0b001;
        ins.funct = 0b100;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = 0;
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "srl r%hu, r%hu", &rd, &rs) == 2){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        Ins ins;
        ins.opcode = 0b001;
        ins.funct = 0b101;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = 0;
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "sra r%hu, r%hu", &rd, &rs) == 2){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        Ins ins;
        ins.opcode = 0b001;
        ins.funct = 0b110;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = 0;
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "mov r%hu, r%hu", &rd, &rs) == 2){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        Ins ins;
        ins.opcode = 0b001;
        ins.funct = 0b111;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = 0;
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "mov r%hu, r%hu%hd", &rd, &rs, &imm) == 2){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (imm >= 0x8 || imm < -0x8)
            printf("[ERROR]: '%s' Constant Limit(%d,%d) Exceeded\n", line, -0x8, 0x7);
        Ins ins;
        ins.opcode = 0b001;
        ins.funct = 0b111;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = imm & 0xF;
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }

    return false;
}

bool parseJump(FILE* out, const char* line, size_t len){
    short offset;
    unsigned short rd, rs;

    if (_snscanf(line, len, "jmp [pc%hd]", &offset) == 1){
        if (offset >= 0x1000 || offset < -0x1000)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x1000, 0xFFF);
        Ins ins;
        ins.opcode = 0b100;
        ins.funct = ((offset >> 6) & 0x7);
        ins.rd = (offset & 0x7);
        ins.rs = ((offset >> 3) & 0x7);
        ins.imm = ((offset >> 9) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "jmp [r%hu%hd]", &rd, &offset) == 2){
        if (rd >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset >= 0x200 || offset < -0x200)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x200, 0x1FF);
        Ins ins;
        ins.opcode = 0b101;
        ins.funct = ((offset >> 3) & 0x7);
        ins.rd = rd;
        ins.rs = (offset & 0x7);
        ins.imm = ((offset >> 6) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }

    if (_snscanf(line, len, "beq [pc%hd], r%hu, r%hu", &offset, &rd, &rs) == 3){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset & 1)
            printf("[ERROR]: '%s' Offset Must Be Even\n", line);
        if (offset >= 0x10 || offset < -0x10)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x10, 0xF);
        Ins ins;
        ins.opcode = 0b110;
        ins.funct = 0b000;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = ((offset >> 1) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "bne [pc%hd], r%hu, r%hu", &offset, &rd, &rs) == 3){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset & 1)
            printf("[ERROR]: '%s' Offset Must Be Even\n", line);
        if (offset >= 0x10 || offset < -0x10)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x10, 0xF);
        Ins ins;
        ins.opcode = 0b110;
        ins.funct = 0b001;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = ((offset >> 1) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "blt [pc%hd], r%hu, r%hu", &offset, &rd, &rs) == 3){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset & 1)
            printf("[ERROR]: '%s' Offset Must Be Even\n", line);
        if (offset >= 0x10 || offset < -0x10)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x10, 0xF);
        Ins ins;
        ins.opcode = 0b110;
        ins.funct = 0b010;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = ((offset >> 1) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "bge [pc%hd], r%hu, r%hu", &offset, &rd, &rs) == 3){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset & 1)
            printf("[ERROR]: '%s' Offset Must Be Even\n", line);
        if (offset >= 0x10 || offset < -0x10)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x10, 0xF);
        Ins ins;
        ins.opcode = 0b110;
        ins.funct = 0b011;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = ((offset >> 1) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "bltu [pc%hd], r%hu, r%hu", &offset, &rd, &rs) == 3){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset & 1)
            printf("[ERROR]: '%s' Offset Must Be Even\n", line);
        if (offset >= 0x10 || offset < -0x10)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x10, 0xF);
        Ins ins;
        ins.opcode = 0b110;
        ins.funct = 0b100;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = ((offset >> 1) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }
    if (_snscanf(line, len, "bgeu [pc%hd], r%hu, r%hu", &offset, &rd, &rs) == 3){
        if (rd >= REG_LIMIT || rs >= REG_LIMIT)
            printf("[ERROR]: '%s' Register Index Limit[%d] Exceeded\n", line, REG_LIMIT);
        if (offset & 1)
            printf("[ERROR]: '%s' Offset Must Be Even\n", line);
        if (offset >= 0x10 || offset < -0x10)
            printf("[ERROR]: '%s' Offset Limit(%d,%d) Exceeded\n", line, -0x10, 0xF);
        Ins ins;
        ins.opcode = 0b110;
        ins.funct = 0b101;
        ins.rd = rd;
        ins.rs = rs;
        ins.imm = ((offset >> 1) & 0xF);
        fwrite(&ins, sizeof(ins), 1, out);
        return true;
    }

    return false;
}

PARSE_FUNC parseFuncs[] = {
    parseConst,
    parseMemory,
    parseArithmatic,
    parseJump
};

int main(int argc, char** argv){
    if (argc != 3){
        printf("Usage: asm [file] [outbin]\n");
        return 1;
    }

    FILE* src = fopen(argv[1], "r");
    if (src == NULL){
        printf("Failed open file %s\n", argv[1]);
    }

    FILE* bin = fopen(argv[2], "wb");
    if (bin == NULL){
        printf("Failed open file %s\n", argv[2]);
    }

    while (!feof(src)){
        char line[LINE_LENGTH];
        bool suc = false;

        int len;
        int ret = fscanf_s(src, "%[^\n]%n", line, LINE_LENGTH, &len);
        if (ret > 0){
            printf("Line[%d]: %s\n", len, line);
            fgetc(src);
        }

        if (len == 0 || ret <= 0){
            printf("Char: %02X\n", fgetc(src));
            continue;
        }

        if (line[0] == ';')
            continue;

        for (size_t i = 0; i < LENGTH_OF(parseFuncs); i++){
            if (parseFuncs[i](bin, line, LINE_LENGTH)){
                suc = true;
                break;
            }
        }

        if (!suc)
            printf("ERROR: unrecognized assembly '%s'\n", line);
    }

    fclose(src);
    fclose(bin);

    return 0;
}